
#include "tjc_hmi.h"

/**
  * @brief  幂次计算函数
  * @param  a 底数
  * @param  n 幂次
  * @retval 幂次计算的结果
  * @note   NULL
  */
static int hmi_pow(int a, int n)
{
	int res = 1;
    while (n--) res *= a;
    return res;
}

/**
  * @brief  发送结束符 0XFF 0XFF 0XFF
  * @param  NULL
  * @retval NULL
  * @note   NULL
  */
static void HMI_SendEnd(void)
{
    HMI_SendByte(0xFF);
    HMI_SendByte(0xFF);
    HMI_SendByte(0xFF);
}

/**
  * @brief  发送字符串
  * @param  str 字符串
  * @retval NULL
  * @note   NULL
  */
static void HMI_SendString(const char *str)
{
    while (*str) HMI_SendByte(*str++);
}

/**
  * @brief  发送数值
  * @param  num 数值
  * @retval NULL
  * @note   NULL
  */
static void HMI_SendNum(int num)
{
    uint8_t sign = (num < 0);   // 数值符号(0:正，1:负)
    uint8_t len = 0;            // 数值长度(不包括符号)
    
    // 获取数值长度
    if (num < 0) num = -num;
    while (num / hmi_pow(10, len)) len++;
    if (num == 0) len++;
    
    // 发送数值
    if (sign) HMI_SendByte('-');
    for (uint8_t i = 0; i < len; i++) HMI_SendByte((num / hmi_pow(10, len-1-i)) % 10 + '0');
}

/**
  * @brief  设置串口屏上文本控件值
  * @param  obj 操作的文本控件对象
  * @param  txt 设置的文本内容
  * @retval NULL
  * @note   例如设置t0文本控件的值为"Hello HMI"：HMI_SetTxt(t0.txt, "Hello HMI");
  */
void HMI_SetTxt(const char *obj, const char *txt)
{
    HMI_SendString(obj);    // obj
    HMI_SendByte('=');      // =
    HMI_SendByte('\"');     // "
    HMI_SendString(txt);    // txt
    HMI_SendByte('\"');     // "
    HMI_SendEnd();          // 0xFF 0xFF 0xFF
}

/**
  * @brief  以格式化的方式设置串口屏上文本控件值
  * @param  obj        操作的文本控件对象
  * @param  format_txt 设置的格式化的文本内容
  * @param  ...        格式化参数
  * @retval NULL
  * @note   例如设置t0文本控件的值为"Hello HMI"：HMI_SetTxt(t0.txt, "Hello HMI");
  */
void HMI_SetTxtFormat(const char* obj, const char* format_txt, ...)
{
    char txt[50] = "";

    va_list arg;
    va_start(arg, format_txt);
    vsprintf(txt, format_txt, arg);
    va_end(arg);

    HMI_SendString(obj);    // obj
    HMI_SendByte('=');      // =
    HMI_SendByte('\"');     // "
    HMI_SendString(txt);    // txt
    HMI_SendByte('\"');     // "
    HMI_SendEnd();          // 0xFF 0xFF 0xFF
}

/**
  * @brief  向串口屏发送指令
  * @param  cmd  操作指令
  * @param  data 指令数据
  * @retval NULL
  * @note   例如发送指定颜色清屏指令：HMI_SendCmd("cls", "BLACK");
  */
void HMI_SendCmd(const char *cmd, const char *data)
{
    HMI_SendString(cmd);    // cmd
    HMI_SendByte(' ');      //  
    HMI_SendString(data);   // data
    HMI_SendEnd();          // 0xFF 0xFF 0xFF
}

/**
  * @brief  以格式化的方式向串口屏发送指令
  * @param  cmd         操作指令
  * @param  format_data 格式化的指令数据
  * @param  ...         格式化参数
  * @retval NULL
  * @note   例如发送指定颜色清屏指令：HMI_SendCmd("cls", "BLACK");
  */
void HMI_SendCmdFormat(const char* cmd, const char* format_data, ...)
{
    char data[50] = "";

    va_list arg;
    va_start(arg, format_data);
    vsprintf(data, format_data, arg);
    va_end(arg);

    HMI_SendString(cmd);    // cmd
    HMI_SendByte(' ');      //  
    HMI_SendString(data);   // data
    HMI_SendEnd();          // 0xFF 0xFF 0xFF
}

/**
  * @brief  设置串口屏上数值控件值
  * @param  obj 操作的数值控件对象
  * @param  num 设置的数值
  * @param  n   当传入浮点数时的小数位数(需要与串口屏上设置的控件属性一致)，若传入整数则该值无效
  * @retval NULL
  * @note   数字与虚拟浮点数均用此函数设置，因为虚拟浮点数本质上还是整数，只是多显示了假小数点
  */
void HMI_SetVal(const char *obj, float num, uint8_t n)
{
    // 浮点数转虚拟浮点数特殊处理
    if (num - (int)num) num *= hmi_pow(10, n);
    
    // 设置数值
    HMI_SendString(obj);    // obj
    HMI_SendByte('=');      // =
    HMI_SendNum(num);       // num
    HMI_SendEnd();          // 0xFF 0xFF 0xFF
}

/**
  * @brief  控制串口屏上的蜂鸣器
  * @param  xms 蜂鸣器鸣叫时长
  * @retval NULL
  * @note   NULL
  */
void HMI_BEEP(uint16_t xms)
{
    HMI_SendString("beep ");    // beep 
    HMI_SendNum(xms);           // txt
    HMI_SendEnd();              // 0xFF 0xFF 0xFF
}
